package cn.tannn.surenessdemo.user.service.impl;

import cn.hutool.core.lang.Assert;
import cn.jdevelops.entity.basics.util.UUIDUtils;
import cn.jdevelops.exception.exception.BusinessException;
import cn.tannn.surenessdemo.annotation.RebuildTree;
import cn.tannn.surenessdemo.controller.dto.AddResourceDTO;
import cn.tannn.surenessdemo.controller.dto.UpdateResourceDTO;
import cn.tannn.surenessdemo.exception.DataConflictException;
import cn.tannn.surenessdemo.user.dao.AuthResourceDao;
import cn.tannn.surenessdemo.user.dao.AuthRoleResourceBindDao;
import cn.tannn.surenessdemo.user.dao.AuthRouteDao;
import cn.tannn.surenessdemo.user.dao.AuthRouteResourceBindDao;
import cn.tannn.surenessdemo.user.entity.AuthResource;
import cn.tannn.surenessdemo.user.entity.AuthRoleResourceBind;
import cn.tannn.surenessdemo.user.entity.AuthRouteResourceBind;
import cn.tannn.surenessdemo.user.service.ResourceService;
import cn.tannn.surenessdemo.user.service.TreePathRoleMatcherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.sql.PreparedStatement;
import java.util.*;

/**
 * @author tomsun28
 * @date 13:09 2019-08-04
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ResourceServiceImpl implements ResourceService {

    private final AuthResourceDao authResourceDao;

    /**
     * 资源 - 路由
     */
    private final AuthRouteResourceBindDao authRouteResourceBindDao;

    private final AuthRouteDao authRouteDao;


    @Override
    @RebuildTree
    public boolean addResource(AddResourceDTO authResource) {
        if (isResourceExist(authResource)) {
            return false;
        } else {
            AuthResource resource = authResource.to(AuthResource.class);
            if (StringUtils.isBlank(resource.getCode())) {
                resource.setCode(UUIDUtils.getInstance().generateShortUuid());
            }
            authResourceDao.saveAndFlush(resource);
            return true;
        }
    }

    @Override
    @RebuildTree
    public boolean addResource(List<AuthResource> authResource) {
        for (AuthResource resource : authResource) {
            try {
                resource.setCode(resource.getUri().replaceAll("/", ""));
                authResourceDao.saveAndFlush(resource);
            } catch (Exception e) {
                log.error("新增资源出错 ==> ", e);
            }
        }
        return true;
    }

    @Override
    public boolean isResourceExist(AddResourceDTO authResource) {
        AuthResource resource = AuthResource.builder()
                .uri(authResource.getUri())
                .method(authResource.getMethod())
                .build();
        Example<AuthResource> example = Example.of(resource);
        return authResourceDao.exists(example);
    }

    @Override
    @RebuildTree
    public boolean updateResource(UpdateResourceDTO authResource) {
        try {
            AuthResource byCode = authResourceDao.findByCode(authResource.getCode());
            AuthResource resource = authResource.to(AuthResource.class);
            Assert.notNull(byCode, () -> new BusinessException("资源不存在"));
            byCode.copy(resource);
            authResourceDao.saveAndFlush(byCode);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    @RebuildTree
    public boolean deleteResource(String resourceCode) {
        if (authResourceDao.existsByCode(resourceCode)) {
            authResourceDao.deleteByCode(resourceCode);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Optional<List<AuthResource>> getAllResource() {
        List<AuthResource> resourceList = authResourceDao.findAll();
        return Optional.of(resourceList);
    }

    @Override
    public Page<AuthResource> getPageResource(Integer currentPage, Integer pageSize) {
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
        return authResourceDao.findAll(pageRequest);
    }

    @Override
    public Set<String> getAllEnableResourcePath() {
        Optional<List<String>> optional = authResourceDao.getEnableResourcePathRoleData();
        return optional.<Set<String>>map(HashSet::new).orElseGet(() -> new HashSet<>(0));
    }

    @Override
    public Set<String> getAllDisableResourcePath() {
        Optional<List<String>> optional = authResourceDao.getDisableResourcePathData();
        return optional.<Set<String>>map(HashSet::new).orElseGet(() -> new HashSet<>(0));
    }

    @Override
    @RebuildTree
    public void enable(List<String> resourceCodes) {
        if (Objects.isNull(resourceCodes) || resourceCodes.isEmpty()) {
            authResourceDao.enableAll();
        } else {
            authResourceDao.changeStatus(resourceCodes, 1);
        }
    }

    @Override
    @RebuildTree
    public void disabled(List<String> resourceCodes) {
        authResourceDao.changeStatus(resourceCodes, 0);
    }

    @Override
    @RebuildTree
    public void interceptAll() {
        authResourceDao.enableAll();
    }

    @Override
    public void authorityResourceRoute(String routeCode, String resourceCodes) {
        AuthRouteResourceBind build = AuthRouteResourceBind.builder()
                .resourceCode(resourceCodes)
                .routeCode(routeCode)
                .build();
        authRouteResourceBindDao.save(build);
    }

    @Override
    public void authorityResourceRoute(String routeCode, List<String> resourceCodes) {
        if (!authRouteDao.existsByCode(routeCode) ) {
            throw new DataConflictException("路由不存在");
        }
        resourceCodes.forEach(it -> {
            try {
                AuthRouteResourceBind build = AuthRouteResourceBind.builder()
                        .resourceCode(it)
                        .routeCode(routeCode)
                        .build();
                authRouteResourceBindDao.saveAndFlush(build);
            }catch (Exception e){
                log.error("路由资源重复",e);
            }
        });
    }

    @Override
    public void deleteAuthorityResourceRoute(String routeCode, String resourceCode) {
        authRouteResourceBindDao.deleteByRouteCodeAndResourceCode(routeCode, resourceCode);
    }
}
